﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.IO;
using System.Xml;
using System.Data;
using System.Data.SqlClient;
using NewsClassifierFreshnessMeasurement.Shared;
using NewsClassifierFreshnessMeasurement.Model;
using NewsClassifierFreshnessMeasurement.QueryExtractor;
using System.Threading;

namespace AutoExtractQueryToXMLFile
{
    public class InputPackage
    {
        public string FactoryDLLFileName { get; set; }
        public string ClassTypeName { get; set; }
        public List<Stream> ListConfigStream { get; set; }
        public List<string> ListStreamAppendix { get; set; }
        
        //the other to get config file. Import data from database.
        public List<int> ListGroupID { get; set; }
        public List<string> ListGroupIDAppendix { get; set; }
        public InputPackage()
        {
            ListConfigStream = new List<Stream>();
            ListStreamAppendix = new List<string>();

            ListGroupID = new List<int>();
            ListGroupIDAppendix = new List<string>();
        }
    }
    public class ProduceFile
    {
        List<News> listNews;
        List<SmallExperiment> listSmallExperiment;
        List<SmallExperimentQueries> listSmallExpeQueries;
        List<KeyValuePair<string,Configuration> > listAppendixConfig;
        QueryExtractorAbstractFactory factory;
        public void Start(List<News> _listNews, InputPackage pkg,string connString)//string factoryFileName, string factoryClassType, List<Stream> listConfigStream, List<string> listAppendix)
        {
            listNews = _listNews;
            listAppendixConfig = new List<KeyValuePair<string, Configuration>>();
            factory = null;
            CreateFactory(pkg.FactoryDLLFileName, pkg.ClassTypeName);
            CreateListAppendixConfig(pkg.ListConfigStream, pkg.ListStreamAppendix);
            CreateListAppendixConfig(pkg.ListGroupID, pkg.ListGroupIDAppendix,connString);
            ProduceProduct();
        }
        public static List<News> GetNewsFromDatabase(string connString,string strSQL,List<string> listQueryNewsID)
        {
            List<News> tmpListNews = new List<News>();
            string queryNewsIDs = "";
            foreach(string s in listQueryNewsID)
            {
                queryNewsIDs += s + ",";
            }
            queryNewsIDs = queryNewsIDs.Substring(0, queryNewsIDs.Length - 1);
            strSQL = "select * from NewsItemList where ID in ("+ queryNewsIDs +")";
            strSQL = strSQL.ToLower();
            if (strSQL.Contains("create") || strSQL.Contains("delete") || strSQL.Contains("update"))
                return tmpListNews;

            SqlConnection sqlConn = new SqlConnection(connString);
            sqlConn.Open();
            SqlCommand cmd = sqlConn.CreateCommand();
            cmd.CommandText = strSQL;
            SqlDataReader reader = cmd.ExecuteReader();
            //get it's market
            SqlConnection sqlConn2 = new SqlConnection(connString);
            sqlConn2.Open();
            SqlCommand cmd2 = sqlConn2.CreateCommand();

            while (reader.Read())
            {
                News news = new News();
                news.ID = Convert.ToInt32(reader["ID"]);
                news.Title = reader["Title"].ToString();
                news.CrawlTime = Convert.ToDateTime(reader["CrawlTime"]);
                news.RawPubDate = reader["PubDate"].ToString();
                news.Link = reader["Link"].ToString();
                news.Description = reader["Description"].ToString();
                news.MD5Code = reader["MD5Code"].ToString();
                news.Source = new NewsSource();
                news.Source.ID = Convert.ToInt32(reader["SourceID"]);
                //get it's market
                cmd2.CommandText = "select * from CompetitorGroup where id = (select groupid from rss where ID = " + news.Source.ID + ")";
                SqlDataReader reader2 = cmd2.ExecuteReader();
                while (reader2.Read())
                {
                    news.Source.Group = new CompetitorGroup()
                    {
                        ID = Convert.ToInt32(reader2["ID"]),
                        Name = reader2["Name"].ToString(),
                        Market = reader2["Market"].ToString(),
                        Description = reader2["Description"].ToString()
                    };
                }
                reader2.Close();
                news.Source.Type = NewsSourceType.RSS;

                tmpListNews.Add(news);
            }
            sqlConn2.Close();
            reader.Close();
            sqlConn.Close();
            return tmpListNews;
        }

        void CreateFactory(string filePath,string factoryTypeName)
        {
            factory = QueryExtractorAbstractFactory.CreateFactoryFromFile(filePath, factoryTypeName);
        }
        public Type[] GetAllTypeName(string filePath)
        {
            Assembly ass = System.Reflection.Assembly.LoadFile(filePath);
            Type[] types = ass.GetTypes();
            return types;
        }
        class NewsQueryCompare : IEqualityComparer<NewsQuery>
        {
            public bool Equals(NewsQuery newsQ1, NewsQuery newsQ2)
            {
                if (Object.ReferenceEquals(newsQ1, newsQ2)) return true;
                if (Object.ReferenceEquals(newsQ1, null) || Object.ReferenceEquals(newsQ2, null))
                    return false;
                if (newsQ1.Query == newsQ2.Query)
                    return true;
                return false;
            }
            public int GetHashCode(NewsQuery newsQ)
            {
                if (Object.ReferenceEquals(newsQ, null)) return 0;

                int hashProductName = newsQ.Query == null ? 0 : newsQ.Query.GetHashCode();

                return hashProductName;
            }
        }
        void ProduceProduct()
        {
            foreach (KeyValuePair<string, Configuration> item in listAppendixConfig)
            {
                IQueryExtractor queryExtractor = factory.CreateQueryExtractor(item.Key, item.Value);

                System.Attribute[] attrs = System.Attribute.GetCustomAttributes(queryExtractor.GetType());  // reflection

                Guid ID = new Guid();
                string description = "";
                foreach (System.Attribute attr in attrs)
                {
                    if (attr is IDAttribute)
                    {
                        IDAttribute a = (IDAttribute)attr;
                        ID = a.ID;
                    }
                    if (attr is DescriptionAttribute)
                    {
                        DescriptionAttribute a = (DescriptionAttribute)attr;
                        description = a.Description;
                    }
                }

                SmallExperiment experiment = new SmallExperiment(ID,description);
                listSmallExperiment.Add(experiment);
                int count = 0;
                foreach (News news in listNews)
                {
                    List<NewsQuery> listNewsQuery = queryExtractor.Extract(news);
                    //distinct
                    List<NewsQuery> listDisNewsQuery = listNewsQuery.Distinct(new NewsQueryCompare()).ToList();
                    SmallExperimentQueries expeQueries = new SmallExperimentQueries(news.ID, experiment.ID);
                    bool isFirst = true;
                    foreach (NewsQuery newsQuery in listDisNewsQuery)
                    {
                        if (isFirst == true)
                        {
                            isFirst = false;
                        }
                            expeQueries.queries.Add(newsQuery.Query);
                    }
                    listSmallExpeQueries.Add(expeQueries);
                    ++count;
                    Console.WriteLine("~~~~~~~~~~~~~~~~~~~~" + count);
                }
            }
        }

        public List<KeyValuePair<string, Configuration>> CreateListAppendixConfig(List<int> listGroupID, List<string> listGroupIDAppendix,string connString)
        {
            if (listGroupID.Count == listGroupIDAppendix.Count)
            {
                int index = 0;
                foreach (int groupID in listGroupID)
                {
                    List<ConfigEntry> listConfigEntry = new List<ConfigEntry>();

                    SqlConnection sqlConn = new SqlConnection(connString);
                    sqlConn.Open();
                    SqlCommand cmd = sqlConn.CreateCommand();
                    cmd.CommandText = "select ID,GroupID,[Key],Value,IsValueCollection,Description from Configuration where GroupID =" + groupID;
                    SqlDataReader reader = cmd.ExecuteReader();
                    while (reader.Read())
                    {
                        ConfigEntry configEntry = new ConfigEntry();
                        configEntry.ID = Convert.ToInt32(reader["ID"]);
                        configEntry.Key = reader["Key"].ToString();
                        configEntry.Value = reader["Value"].ToString();
                        configEntry.IsValueCollection = Convert.ToBoolean(reader["IsValueCollection"]);
                        configEntry.Description = reader["Description"].ToString();
                        configEntry.Delimiter = ",";

                        listConfigEntry.Add(configEntry);
                    }
                    Configuration config = new Configuration(listConfigEntry);
                    KeyValuePair<string, Configuration> tmp = new KeyValuePair<string, Configuration>(listGroupIDAppendix.ElementAt(index), config);
                    listAppendixConfig.Add(tmp);
                    ++index;

                    sqlConn.Close();
                }
            }
            return listAppendixConfig;
        }

        public List<KeyValuePair<string, Configuration>> CreateListAppendixConfig(List<Stream> listFileStream, List<string> listAppendix)
        {
            if (listFileStream.Count == listAppendix.Count)
            {
                int index = 0;
                foreach (Stream stream in listFileStream)
                {
                    List<ConfigEntry> listConfigEntry = new List<ConfigEntry>();
                    XmlReader reader = XmlReader.Create(stream);
                    reader.MoveToContent();

                    while (reader.Read())
                    {
                        if (reader.NodeType == XmlNodeType.Element)
                        {
                            if (reader.Name == "ConfigEntry")
                            {
                                ConfigEntry configEntry = new ConfigEntry();

                                reader.ReadToFollowing("ID");
                                configEntry.ID = reader.ReadElementContentAsInt("ID", "");

                                reader.ReadToFollowing("Key");
                                configEntry.Key = reader.ReadElementContentAsString("Key", "");

                                reader.ReadToFollowing("Value");
                                configEntry.Value = reader.ReadElementContentAsString("Value","");

                                reader.ReadToFollowing("IsValueCollection");
                                configEntry.IsValueCollection = reader.ReadElementContentAsBoolean("IsValueCollection", "");

                                reader.ReadToFollowing("Description");
                                configEntry.Description = reader.ReadElementContentAsString("Description", "");
                                

                                reader.ReadToFollowing("Delimiter");
                                configEntry.Delimiter = reader.ReadElementContentAsString("Delimiter", "");

                                listConfigEntry.Add(configEntry);
                            }
                        }
                    }
                    Configuration config = new Configuration(listConfigEntry);
                    KeyValuePair<string, Configuration> tmp = new KeyValuePair<string, Configuration>(listAppendix.ElementAt(index), config);
                    listAppendixConfig.Add(tmp);
                    ++index;
                    stream.Close();
                }
            }
            else
            {
                throw new ArgumentException("filePath's count don't equal to appendix's count");
            }
            return listAppendixConfig;
        }
        public ProduceFile(List<News> _listNews,List<SmallExperiment> _listSmallExperiment,List<SmallExperimentQueries> _listSmallExpeQueries)
        {
            listNews = _listNews;
            listSmallExperiment = _listSmallExperiment;
            listSmallExpeQueries = _listSmallExpeQueries;
        }
        void Print()
        {
            foreach (SmallExperiment e in listSmallExperiment)
            {
                Console.WriteLine(e.ID + " " + e.name);
            }
            foreach (SmallExperimentQueries q in listSmallExpeQueries)
            {
                Console.WriteLine(q.experimentID + " " + q.newsID + " ");
                foreach (string s in q.queries)
                {
                    Console.Write(s + " ");
                }
                Console.WriteLine("");
            }
        }
        public static void CreateFile(string filePath,List<News> _listNews,List<SmallExperiment> _listSmallExperiment, List<SmallExperimentQueries> _listSmallExpeQueries)
        {
            FileStream fs = new FileStream(filePath, FileMode.Create);
            XmlTextWriter w = new XmlTextWriter(fs, Encoding.UTF8);
            w.Formatting = Formatting.Indented;
            w.WriteStartDocument();
            w.WriteStartElement("Task");
            

            //write News element
            w.WriteStartElement("News");
            foreach (News news in _listNews)
            {
                w.WriteStartElement("NewsItem");
                w.WriteElementString("ID", Convert.ToString(news.ID));
                w.WriteElementString("Title", news.Title);
                w.WriteElementString("Content", news.Description);
                w.WriteElementString("Market", news.Source.Group.Market);
                w.WriteEndElement();
            }
            w.WriteEndElement();


            //write Exp element
            w.WriteStartElement("Experiments");
            foreach (SmallExperiment smallExpe in _listSmallExperiment)
            {
                w.WriteStartElement("Experiment");
                w.WriteElementString("ID", Convert.ToString(smallExpe.ID));
                w.WriteElementString("Name", smallExpe.name);
                w.WriteEndElement();
            }
            w.WriteEndElement();

            //write Experiments element
            w.WriteStartElement("ExperimentResults");
            foreach (SmallExperimentQueries q in _listSmallExpeQueries)
            {
                w.WriteStartElement("ExperimentResult");
                w.WriteElementString("NewsID", Convert.ToString(q.newsID));
                w.WriteElementString("ExpID", Convert.ToString(q.experimentID));
                w.WriteStartElement("Queries");
                foreach (string query in q.queries)
                {
                    w.WriteElementString("Query", query);
                }
                w.WriteEndElement();
                w.WriteEndElement();
            }
            w.WriteEndElement();

            w.WriteEndElement();
            w.WriteEndDocument();
            w.Flush();
            fs.Close();
            Console.WriteLine("Document created.");
        }
    }
}
